home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / ipServer / tcpInput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-25  |  47.6 KB  |  1,798 lines

  1. /* 
  2.  * tcpInput.c --
  3.  *
  4.  *    Routines to handle TCP packets. The packet is examined for
  5.  *    proper format before the data are saved in a socket's recv buffer.
  6.  *
  7.  *    The algorithms in this file are based on the functional specification
  8.  *    of the Transmission Control Protocol in RFC793 (Sept. 1981).
  9.  *
  10.  *    Security and precedence checks are not performed on the packet.
  11.  *
  12.  *     Based on the following 4.3BSD file:
  13.  *    "@(#)tcp_input.c 7.18 (Berkeley) 5/14/88"
  14.  *
  15.  * Copyright 1987 Regents of the University of California
  16.  * All rights reserved.
  17.  * Permission to use, copy, modify, and distribute this
  18.  * software and its documentation for any purpose and without
  19.  * fee is hereby granted, provided that the above copyright
  20.  * notice appear in all copies.  The University of California
  21.  * makes no representations about the suitability of this
  22.  * software for any purpose.  It is provided "as is" without
  23.  * express or implied warranty.
  24.  */
  25.  
  26. #ifndef lint
  27. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/tcpInput.c,v 1.14 91/10/25 10:47:56 mottsmth Exp $ SPRITE (Berkeley)";
  28. #endif not lint
  29.  
  30.  
  31. #include "sprite.h"
  32. #include "netInet.h"
  33. #include "ipServer.h"
  34. #include "stat.h"
  35. #include "ip.h"
  36. #include "tcp.h"
  37. #include "tcpInt.h"
  38. #include "socket.h"
  39. #include "route.h"
  40.  
  41. #include "list.h"
  42. #include "fs.h"
  43.  
  44. /*
  45.  * Global variables for
  46.  */
  47. int    tcpISS = 0;
  48. int    tcpReXmtThresh = 3;
  49.  
  50. /*
  51.  * Information about data segments on the reassembly queue of a socket's TCB.
  52.  */
  53. typedef struct {
  54.     List_Links        links;        /* Used to chain elements together. */
  55.     Address        data;        /* Ptr to the segment data. */
  56.     Address        base;        /* Ptr to the segment base. This address
  57.                      * is used with free. */
  58.     int            len;        /* Length of the data. */
  59.     unsigned short    flags;        /* TCP header flags of the segment. */
  60.     TCPSeqNum        seqNum;        /* TCP sequence number of the segment.*/
  61. } ReassElement;
  62.  
  63.  
  64. static void    Input();
  65. static void    ProcessOptions();
  66. extern int    TCPCalcMaxSegSize();
  67. static void    CalcFreeSpace();
  68. static unsigned short    Reassemble();
  69.  
  70.  
  71. /*
  72.  *----------------------------------------------------------------------
  73.  *
  74.  * TCP_MemBin --
  75.  *
  76.  *    Bucketize various structures that are dynamically allocated by TCP.
  77.  *
  78.  * Results:
  79.  *    None.
  80.  *
  81.  * Side effects:
  82.  *    Calls Mem_Bin.
  83.  *
  84.  *----------------------------------------------------------------------
  85.  */
  86.  
  87. void
  88. TCP_MemBin()
  89. {
  90.     Mem_Bin(sizeof(ReassElement));
  91.     Mem_Bin(sizeof(TCPControlBlock));
  92.     Mem_Bin(sizeof(TCPConnectInfo));
  93.     Mem_Bin(sizeof(Net_TCPHeader));
  94.     Mem_Bin(TCP_BUF_SIZE);
  95. }
  96.  
  97. /*
  98.  *----------------------------------------------------------------------
  99.  *
  100.  * TCP_Init --
  101.  *
  102.  *    Initialize TCP data structures.
  103.  *
  104.  * Results:
  105.  *    None.
  106.  *
  107.  * Side effects:
  108.  *    A routine is set up to handle TCP packets. The initial send
  109.  *    sequence number is determined.
  110.  *
  111.  *----------------------------------------------------------------------
  112.  */
  113.  
  114. void
  115. TCP_Init(seconds)
  116.     int    seconds;    /* Used to set the initial send sequence #. */
  117. {
  118.     if (ips_Debug) {
  119.     (void) (void) fprintf(stderr, "TCP: sizeof(tcb) = %d\n", 
  120.                 sizeof(TCPControlBlock));
  121.     }
  122.     tcpISS = seconds;
  123.     IP_SetProtocolHandler(NET_IP_PROTOCOL_TCP, Input);
  124.     TCPTimerInit();
  125. }
  126.  
  127.  
  128. /*
  129.  *----------------------------------------------------------------------
  130.  *
  131.  * Input --
  132.  *
  133.  *    This routine accepts IP datagrams and processes data for
  134.  *    this protocol.
  135.  *
  136.  *    TCP input routine, follows pages 65-76 of the
  137.  *    protocol specification dated September, 1981 very closely.
  138.  *
  139.  * Results:
  140.  *    None.
  141.  *
  142.  * Side effects:
  143.  *    Many.
  144.  *
  145.  *----------------------------------------------------------------------
  146.  */
  147.  
  148. /*ARGSUSED*/
  149. static void
  150. Input(netID, packetPtr)
  151.     Rte_NetID    netID;        /* Which network the packet came from. */
  152.     IPS_Packet    *packetPtr;    /* Packet descriptor. */
  153. {
  154.     register Net_TCPHeader    *tcpHdrPtr;
  155.     register Net_IPHeader    *ipHdrPtr;
  156.     register TCPControlBlock    *tcbPtr;
  157.     register unsigned short    headerFlags;
  158.     int                dataLen;
  159.     int                offset;
  160.     Address            data;
  161.     Net_TCPHeader        saveHeader;
  162.     Sock_InfoPtr        sockPtr;
  163.     TCPState             oldState;
  164.     int             toDrop;
  165.     int             acked;
  166.     Boolean            ourFinIsAcked;
  167.     int             needOutput = FALSE;
  168.     int                iss = 0;
  169.     Boolean            freePacket = TRUE;
  170.  
  171.     stats.tcp.recv.total++;
  172.  
  173.     ipHdrPtr  = packetPtr->ipPtr;
  174.     tcpHdrPtr =(Net_TCPHeader *) ((Address) ipHdrPtr + (ipHdrPtr->headerLen*4));
  175.     dataLen   = ipHdrPtr->totalLen - (ipHdrPtr->headerLen*4);
  176.     data      = (Address) tcpHdrPtr;
  177.  
  178.     if (dataLen < sizeof(Net_TCPHeader)) {
  179.     stats.tcp.recv.shortLen++;
  180.     free(packetPtr->base);
  181.     return;
  182.     }
  183.  
  184.     /*
  185.      * Make sure the shecksum is valid.
  186.      */
  187.     {
  188.     Net_IPPseudoHdr        pseudoHdr;
  189.     unsigned short        sum;
  190.  
  191.     /*
  192.      * The checksum is computed for the IP "pseudo-header" and
  193.      * the TCP header and data. When the TCP checksum was calculated,
  194.      * the checksum field in the header was set to zero. When we 
  195.      * recalculate the value, we don't zero the field so the computed 
  196.      * value should be zero if the packet didn't get garbled.
  197.      */
  198.     pseudoHdr.source    = ipHdrPtr->source;
  199.     pseudoHdr.dest        = ipHdrPtr->dest;
  200.     pseudoHdr.zero        = 0;
  201.     pseudoHdr.protocol    = ipHdrPtr->protocol;
  202.     pseudoHdr.len        = Net_HostToNetShort((unsigned short)dataLen);
  203.     sum = Net_InetChecksum2(dataLen, (Address) tcpHdrPtr, &pseudoHdr);
  204.     if (sum != 0) {
  205.         if (ips_Debug) {
  206.         (void) fprintf(stderr, "TCP: checksum != 0 (%x)\n", sum);
  207.         }
  208.  
  209.         stats.tcp.recv.badChecksum++;
  210.         free(packetPtr->base);
  211.         return;
  212.     }
  213.     }
  214.  
  215.     /*
  216.      * Make sure the data offset is valid.
  217.      */
  218.  
  219.     offset = tcpHdrPtr->dataOffset * 4;
  220.     if ((offset < sizeof(Net_TCPHeader)) || (offset > dataLen)) {
  221.     stats.tcp.recv.badOffset++;
  222.     if (ips_Debug) {
  223.         (void) fprintf(stderr, "TCP Input: bad offset (%d)\n", offset);
  224.     }
  225.     free(packetPtr->base);
  226.     return;
  227.     }
  228.     dataLen -= offset;
  229.     data    += offset;
  230.  
  231.     /*
  232.      * The packetPtr must contain current values of the data length and
  233.      * buffer address. Whenever packetPtr is used below, it will be
  234.      * updated with the latest values of dataLen and data.
  235.      */
  236.     packetPtr->dataLen = dataLen;
  237.     packetPtr->data    = data;
  238.  
  239.  
  240.     /*
  241.      * Convert TCP protocol specific fields to host format.
  242.      */
  243. #ifdef notdef
  244.     tcpHdrPtr->srcPort     = Net_NetToHostShort(tcpHdrPtr->srcPort);
  245.     tcpHdrPtr->destPort     = Net_NetToHostShort(tcpHdrPtr->destPort);
  246. #endif
  247.     tcpHdrPtr->window     = Net_NetToHostShort(tcpHdrPtr->window);
  248.     tcpHdrPtr->seqNum     = Net_NetToHostInt(tcpHdrPtr->seqNum);
  249.     tcpHdrPtr->ackNum     = Net_NetToHostInt(tcpHdrPtr->ackNum);
  250.     tcpHdrPtr->urgentOffset = Net_NetToHostShort(tcpHdrPtr->urgentOffset);
  251.     headerFlags = tcpHdrPtr->flags;
  252.  
  253.     if (ips_Debug) {
  254.     (void) fprintf(stderr, 
  255.             "TCP Input: %d bytes <%x,%d> <-- <%x,%d,#%d>\n\t",
  256.             dataLen,
  257.             Net_NetToHostInt(ipHdrPtr->dest), 
  258.             Net_NetToHostShort(tcpHdrPtr->destPort),
  259.             Net_NetToHostInt(ipHdrPtr->source),
  260.             Net_NetToHostShort(tcpHdrPtr->srcPort),
  261.             ipHdrPtr->ident);
  262.     TCPPrintHdrFlags(stderr, headerFlags);
  263.     (void) fprintf(stderr, "  seq=%d,  ack=%d\n",
  264.             tcpHdrPtr->seqNum,tcpHdrPtr->ackNum);
  265.     }
  266.  
  267.     /*
  268.      * Locate socket/tcb info for the segment.
  269.      */
  270.  
  271. findSock:
  272.  
  273.     tcbPtr = (TCPControlBlock *) NULL;
  274.  
  275.     sockPtr = (Sock_InfoPtr) Sock_Match(TCP_PROTO_INDEX, 
  276.             ipHdrPtr->dest, tcpHdrPtr->destPort, 
  277.             ipHdrPtr->source, tcpHdrPtr->srcPort, 
  278.             TRUE);
  279.  
  280.     /*
  281.      * If the state is CLOSED (i.e., TCB does not exist) then
  282.      * all data in the incoming segment is discarded. If the TCB exists
  283.      * but is in the CLOSED state, then it's embryonic so it should
  284.      * do a listen or a connect soon.
  285.      */
  286.     if (sockPtr == (Sock_InfoPtr) NULL) {
  287.     goto dropWithReset;
  288.     }
  289.  
  290.     tcbPtr = TCPSockToTCB(sockPtr);
  291.     if (tcbPtr == (TCPControlBlock *) NULL) {
  292.     goto dropWithReset;
  293.     }
  294.     if (tcbPtr->state == CLOSED) {
  295.     goto drop;
  296.     }
  297.  
  298.     if (Sock_IsOptionSet(sockPtr, NET_OPT_DEBUG)) {
  299.     oldState = tcbPtr->state;
  300.     saveHeader = *tcpHdrPtr;
  301.     }
  302.  
  303.  
  304.  
  305.     /*
  306.      * p. 65
  307.      *
  308.      * If the socket is in the LISTEN state, then ignore the segment if the
  309.      * RESET bit is set.  If the segment contains an ACK, then it is bad --
  310.      * send a RESET to the peer.  If the segment does not contain a SYN, then 
  311.      * it is not interesting and it is dropped.  Don't bother responding if 
  312.      * the destination was a broadcast.  Otherwise initialize 
  313.      * tcbPtr->recv.next, and tcbPtr->recv.initial, select a value for
  314.      * tcbPtr->send.initial, and send a segment with:
  315.      *
  316.      *     <SEQ=ISS><ACK=RECV.NEXT><CTL=SYN,ACK> 
  317.      *
  318.      * Also initialize tcbPtr->send.next to tcbPtr->send.initial+1 and
  319.      * tcbPtr->send.unAck to tcbPtr->send.initial.  Fill in the remote
  320.      * peer address fields if not previously specified.  Enter the
  321.      * SYN_RECEIVED state, and process any other fields of this segment 
  322.      * in this state.
  323.      */
  324.  
  325.     if (tcbPtr->state == LISTEN) {
  326.  
  327.     if (headerFlags & NET_TCP_RST_FLAG) {
  328.         goto drop;
  329.     }
  330.     if (headerFlags & NET_TCP_ACK_FLAG) {
  331.         goto dropWithReset;
  332.     }
  333.     if ((headerFlags & NET_TCP_SYN_FLAG) == 0) {
  334.         goto drop;
  335.     }
  336.     if (Rte_IsBroadcastAddr(ipHdrPtr->dest)) {
  337.         goto drop;
  338.     }
  339.  
  340.     /*
  341.      * Try to create a new socket and TCB. If there's and error then
  342.      * drop the segment.
  343.      */
  344.     sockPtr = TCPCloneConnection(sockPtr, 
  345.             ipHdrPtr->dest, 
  346.             tcpHdrPtr->destPort, ipHdrPtr->source, tcpHdrPtr->srcPort);
  347.     if (sockPtr == (Sock_InfoPtr) NULL) {
  348.         goto drop;
  349.     }
  350.     tcbPtr = TCPSockToTCB(sockPtr);
  351.  
  352.  
  353.     TCPMakeTemplateHdr(sockPtr, tcbPtr);
  354.     if (offset > sizeof(Net_TCPHeader)) {
  355.         ProcessOptions(offset, tcpHdrPtr, tcbPtr);
  356.     }
  357.  
  358.     /*
  359.      * Select the initial send and receive sequence numbers and initialize
  360.      * the other fields.
  361.      */
  362.  
  363.     if (iss != 0) {
  364.         tcbPtr->send.initial = iss;
  365.     } else {
  366.         tcbPtr->send.initial = tcpISS;
  367.     }
  368.     tcpISS += TCP_INIT_SEND_SEQ_INCR/2;
  369.     tcbPtr->recv.initial = tcpHdrPtr->seqNum;
  370.     TCP_SEND_SEQ_INIT(tcbPtr);
  371.     TCP_RECV_SEQ_INIT(tcbPtr);
  372.  
  373.     tcbPtr->flags |= TCP_ACK_NOW;
  374.     tcbPtr->state = SYN_RECEIVED;
  375.     tcbPtr->idle = 0;
  376.     tcbPtr->timer[TCP_TIMER_KEEP_ALIVE] = TCP_KEEP_TIME_INIT;
  377.     CalcFreeSpace(sockPtr, tcbPtr);
  378.     stats.tcp.accepts++;
  379.     goto trimThenUpdateWindow;
  380.  
  381.     } 
  382.  
  383.  
  384.  
  385.     if (offset > sizeof(Net_TCPHeader)) {
  386.     ProcessOptions(offset, tcpHdrPtr, tcbPtr);
  387.     }
  388.  
  389.     /*
  390.      * A segment was received on an active connection.  Reset the idle time 
  391.      * and the keep-alive timer.
  392.      */
  393.     tcbPtr->idle = 0;
  394.     tcbPtr->timer[TCP_TIMER_KEEP_ALIVE] = tcpKeepIdle;
  395.     CalcFreeSpace(sockPtr, tcbPtr);
  396.     
  397.  
  398.  
  399.     if (tcbPtr->state == SYN_SENT) {
  400.  
  401.     /*
  402.      * p. 66
  403.      *
  404.      * If the TCB state is SYN_SENT:
  405.      *    if seg contains an ACK, but not for our SYN, drop the input.
  406.      *    if seg contains a RESET, then drop the connection.
  407.      *    if seg does not contain SYN, then drop it.
  408.      * Otherwise this is an acceptable SYN segment.
  409.      *    1) Initialize tcbPtr->recv.next and tcbPtr->recv.initial
  410.      *    2) If seg contains ack then advance tcbPtr->send.unAck.
  411.      *    3) If SYN has been acked, change to ESTABLISHED state, else
  412.      *    change to the SYN_RCVD state.
  413.      *    4) Arrange for segment to be acked (eventually)
  414.      *    5) Continue processing the rest of the data/controls, 
  415.      *       beginning with the URG bit.
  416.      */
  417.  
  418.     if ((headerFlags & NET_TCP_ACK_FLAG) &&
  419.         (TCP_SEQ_LE(tcpHdrPtr->ackNum, tcbPtr->send.initial) ||
  420.          TCP_SEQ_GT(tcpHdrPtr->ackNum, tcbPtr->send.maxSent))) {
  421.         goto dropWithReset;
  422.     }
  423.  
  424.     if (headerFlags & NET_TCP_RST_FLAG) {
  425.         if (headerFlags & NET_TCP_ACK_FLAG) {
  426.         TCPDropConnection(sockPtr, tcbPtr, 
  427.                     (ReturnStatus)NET_CONNECT_REFUSED);
  428.         tcbPtr = NULL;
  429.         }
  430.         goto drop;
  431.     }
  432.  
  433.     if ((headerFlags & NET_TCP_SYN_FLAG) == 0) {
  434.         goto drop;
  435.     }
  436.  
  437.     if (headerFlags & NET_TCP_ACK_FLAG) {
  438.         tcbPtr->send.unAck = tcpHdrPtr->ackNum;
  439.         if (TCP_SEQ_LT(tcbPtr->send.next, tcbPtr->send.unAck)) {
  440.         tcbPtr->send.next = tcbPtr->send.unAck;
  441.         }
  442.     }
  443.  
  444.     tcbPtr->timer[TCP_TIMER_REXMT] = 0;
  445.     tcbPtr->recv.initial = tcpHdrPtr->seqNum;
  446.     TCP_RECV_SEQ_INIT(tcbPtr);
  447.     tcbPtr->flags |= TCP_ACK_NOW;
  448.  
  449.     if ((headerFlags & NET_TCP_ACK_FLAG) && 
  450.         TCP_SEQ_GT(tcbPtr->send.unAck, tcbPtr->send.initial)) {
  451.  
  452.         stats.tcp.connects++;
  453.         Sock_Connected(sockPtr);
  454.         tcbPtr->state = ESTABLISHED;
  455.         tcbPtr->maxSegSize = MIN(tcbPtr->maxSegSize, 
  456.                         TCPCalcMaxSegSize(tcbPtr));
  457.         packetPtr->data = data;
  458.         packetPtr->dataLen = dataLen;
  459.         (void) Reassemble(sockPtr, tcbPtr, (Net_TCPHeader *)NULL,
  460.                 packetPtr);
  461.         /*
  462.          * If we didn't have to retransmit the SYN, use its round-trip
  463.          * time as our initial smooth rrt and rtt var.
  464.          */
  465.         if (tcbPtr->rtt != 0) {
  466.         tcbPtr->srtt = tcbPtr->rtt << 3;
  467.         tcbPtr->rttvar = tcbPtr->rtt << 1;
  468.         TCP_TIMER_RANGESET(tcbPtr->rxtcur, 
  469.             ((tcbPtr->srtt >> 2) + tcbPtr->rttvar) >> 1,
  470.             TCP_MIN_REXMT_TIME, TCP_MAX_REXMT_TIME);
  471.         tcbPtr->rtt = 0;
  472.         }
  473.     } else {
  474.         tcbPtr->state = SYN_RECEIVED;
  475.     }
  476.  
  477. trimThenUpdateWindow:
  478.  
  479.     /*
  480.      * Advance tcpHdrPtr->seqNum to correspond to first data byte.
  481.      * If there's data, remove the excess to stay within window, 
  482.      * dropping the FIN if necessary.
  483.      */
  484.     tcpHdrPtr->seqNum++;
  485.     if (dataLen > tcbPtr->recv.window) {
  486.         toDrop = dataLen - tcbPtr->recv.window;
  487.         dataLen = tcbPtr->recv.window;
  488.         headerFlags &= ~NET_TCP_FIN_FLAG;
  489.         stats.tcp.recv.packAfterWin++;
  490.         stats.tcp.recv.byteAfterWin += toDrop;
  491.     }
  492.     tcbPtr->send.updateSeqNum = tcpHdrPtr->seqNum - 1;
  493.     tcbPtr->recv.urgentPtr = tcpHdrPtr->seqNum;
  494.     goto updateWindow;
  495.     }
  496.  
  497.     /*
  498.      * p. 69
  499.      *
  500.      * Processing for states other than LISTEN or SYN_SENT.
  501.      * First check that at least some bytes of the segment are within 
  502.      * the receive window.  If the segment begins before recv.next,
  503.      * drop leading data (and SYN); if nothing is left, just ack.
  504.      */
  505.  
  506.     toDrop = tcbPtr->recv.next - tcpHdrPtr->seqNum;
  507.     if (toDrop > 0) {
  508.     if (headerFlags & NET_TCP_SYN_FLAG) {
  509.         headerFlags &= ~NET_TCP_SYN_FLAG;
  510.         tcpHdrPtr->seqNum++;
  511.  
  512.         if (tcpHdrPtr->urgentOffset > 1) {
  513.         tcpHdrPtr->urgentOffset--;
  514.         } else {
  515.         headerFlags &= ~NET_TCP_URG_FLAG;
  516.         }
  517.         toDrop--;
  518.     }
  519.  
  520.     /*
  521.      * If we need to drop more data than what's in the segment, then
  522.      * drop the segment after ACKing it.
  523.      */
  524.     if ((toDrop > dataLen) ||
  525.         ((toDrop == dataLen) && ((headerFlags & NET_TCP_FIN_FLAG) == 0))) {
  526.  
  527.         stats.tcp.recv.dupPack++;
  528.         stats.tcp.recv.dupByte += dataLen;
  529.         /*
  530.          * If the segment is just one to the left of the window,
  531.          * check two special cases:
  532.          * 1. Don't toss RST in response to 4.2-style keepalive.
  533.          * 2. If the only thing to drop is a FIN, we can drop
  534.          *    it, but check the ACK or we will get into FIN
  535.          *    wars if our FINs crossed (both CLOSING).
  536.          * In either case, send an ACK to resynchronize,
  537.          * but keep on processing for RST or ACK.
  538.          */
  539.  
  540.         if (((headerFlags & NET_TCP_FIN_FLAG) && (toDrop == dataLen+1)) 
  541. #ifdef TCP_COMPAT_42
  542.           || ((headerFlags & NET_TCP_RST_FLAG) && 
  543.             (tcpHdrPpr->sequm == tcbPtr->recv.next -1))
  544. #endif TCP_COMPAT_42
  545.         ) {
  546.         toDrop = dataLen;
  547.         headerFlags &= ~NET_TCP_FIN_FLAG;
  548.         tcbPtr->flags |= TCP_ACK_NOW;
  549.         } else {
  550.         goto dropAfterAck;
  551.         }
  552.     } else {
  553.         stats.tcp.recv.partDupPack++;
  554.         stats.tcp.recv.partDupByte += toDrop;
  555.     }
  556.  
  557.     /*
  558.      * Drop data from the front of the segment. This is done by adjusting
  559.      * the start of the data buffer pointer and length. Since the urgent
  560.      * pointer is relative to the segment seqNum, it must be adjusted or
  561.      * cleared.
  562.      */
  563.     tcpHdrPtr->seqNum += toDrop;
  564.     dataLen          -= toDrop;
  565.     data          += toDrop;
  566.  
  567.     if (tcpHdrPtr->urgentOffset > toDrop) {
  568.         tcpHdrPtr->urgentOffset -= toDrop;
  569.     } else {
  570.         headerFlags &= ~NET_TCP_URG_FLAG;
  571.         tcpHdrPtr->urgentOffset = 0;
  572.     }
  573.     }
  574.  
  575.     /*
  576.      *
  577.      * If new data are received on a connection after the
  578.      * user processes are gone, then RESET the other end.
  579.      */
  580.  
  581.     if (!Sock_HasUsers(sockPtr) && 
  582.         TCP_HAVE_SENT_FIN(tcbPtr->state) &&    (dataLen > 0)) {
  583.  
  584.     TCPCloseConnection(sockPtr, tcbPtr);
  585.     sockPtr = NULL;
  586.     tcbPtr = NULL;
  587.     stats.tcp.recv.afterClose++;
  588.     goto dropWithReset;
  589.     }
  590.  
  591.     /*
  592.      * If the segment ends after the window, drop trailing data (and
  593.      * PUSH and FIN bits, too). If there's no data left, then just ACK.
  594.      */
  595.  
  596.     toDrop = (tcpHdrPtr->seqNum + dataLen) - 
  597.                 (tcbPtr->recv.next + tcbPtr->recv.window);
  598.     if (toDrop > 0) {
  599.     stats.tcp.recv.packAfterWin++;
  600.     if (toDrop >= dataLen) {
  601.         stats.tcp.recv.byteAfterWin += dataLen;
  602.         /*
  603.          * If a new connection request is received while in the 
  604.          * TIME_WAIT state, drop the old connection and start over 
  605.          * if the sequence numbers are above the previous ones.
  606.          */
  607.         if ((headerFlags & NET_TCP_SYN_FLAG) &&
  608.         (tcbPtr->state == TIME_WAIT) &&
  609.         TCP_SEQ_GT(tcpHdrPtr->seqNum, tcbPtr->recv.next)) {
  610.  
  611.         iss = tcbPtr->recv.next + TCP_INIT_SEND_SEQ_INCR ;
  612.         TCPCloseConnection(sockPtr, tcbPtr);
  613.         goto findSock;
  614.         }
  615.         /*
  616.          * If window is closed can only take segments at
  617.          * window edge, and have to drop data and PUSH from
  618.          * incoming segments.  Continue processing, but
  619.          * remember to ack.  Otherwise, drop segment
  620.          * and ack.
  621.          */
  622.         if ((tcbPtr->recv.window == 0) && 
  623.         (tcpHdrPtr->seqNum == tcbPtr->recv.next)) {
  624.         stats.tcp.recv.winProbe++;
  625.         tcbPtr->flags |= TCP_ACK_NOW;
  626.         } else {
  627.         goto dropAfterAck;
  628.         }
  629.     } else {
  630.         stats.tcp.recv.byteAfterWin += toDrop;
  631.     }
  632.     dataLen -= toDrop;
  633.     headerFlags &= ~(NET_TCP_PSH_FLAG|NET_TCP_FIN_FLAG);
  634.     }
  635.  
  636.     /*
  637.      * p. 70
  638.      *
  639.      * Step 2: Check the RESET bit.
  640.      *
  641.      *
  642.      * If the RESET bit is set, and the tcb is in the 
  643.      *   a) SYN_RECEIVED state:
  644.      *        If passive open, return to LISTEN state.
  645.      *        If active open, inform the user that the connection was refused.
  646.      *   b) ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT states:
  647.      *        Inform the user that the connection was reset, and close 
  648.      *        the tcb.
  649.      *   c) CLOSING, LAST_ACK, TIME_WAIT states:
  650.      *        Close the tcb.
  651.      */
  652.  
  653.     if (headerFlags & NET_TCP_RST_FLAG) {
  654.     switch (tcbPtr->state) {
  655.  
  656.         case SYN_RECEIVED:
  657.         TCPDropConnection(sockPtr, tcbPtr, 
  658.                     (ReturnStatus)NET_CONNECT_REFUSED);
  659.         tcbPtr = NULL;
  660.         goto drop;
  661.  
  662.         case ESTABLISHED:
  663.         case FIN_WAIT_1:
  664.         case FIN_WAIT_2:
  665.         case CLOSE_WAIT:
  666.         TCPDropConnection(sockPtr, tcbPtr, 
  667.                 (ReturnStatus)NET_CONNECTION_RESET);
  668.         tcbPtr = NULL;
  669.         goto drop;
  670.  
  671.         case CLOSING:
  672.         case LAST_ACK:
  673.         case TIME_WAIT:
  674.         TCPCloseConnection(sockPtr, tcbPtr);
  675.         tcbPtr = NULL;
  676.         goto drop;
  677.     }
  678.     }
  679.  
  680.     /*
  681.      * p. 71
  682.      *
  683.      * Step 3: check security and precedence.
  684.      *
  685.      * (not implemented.)
  686.      *
  687.      */
  688.  
  689.     /*
  690.      * p. 71
  691.      *
  692.      * State 4: check the SYN bit.
  693.      *
  694.      * If the SYN is in the window, it is an error so send a RESET and
  695.      * drop the connection.
  696.      */
  697.     if (headerFlags & NET_TCP_SYN_FLAG) {
  698.     TCPDropConnection(sockPtr, 
  699.             tcbPtr, (ReturnStatus)NET_CONNECTION_RESET);
  700.     tcbPtr = NULL;
  701.     goto dropWithReset;
  702.     }
  703.  
  704.     /*
  705.      * p. 72
  706.      *
  707.      * Step 5: check the ACK bit.
  708.      *
  709.      * If the ACK bit is off, we drop the segment and return.
  710.      */
  711.  
  712.     if ((headerFlags & NET_TCP_ACK_FLAG) == 0) {
  713.     goto drop;
  714.     }
  715.     
  716.     switch (tcbPtr->state) {
  717.  
  718.     /*
  719.      * In the SYN_RECEIVED state, if the ACK acknowledges our SYN 
  720.      * then we enter the ESTABLISHED state and continue processing, 
  721.      * otherwise we send an RESET.
  722.      */
  723.  
  724.     case SYN_RECEIVED:
  725.  
  726.         if (TCP_SEQ_GT(tcbPtr->send.unAck, tcpHdrPtr->ackNum) ||
  727.         TCP_SEQ_GT(tcpHdrPtr->ackNum, tcbPtr->send.maxSent)) {
  728.         goto dropWithReset;
  729.         }
  730.         stats.tcp.connects++;
  731.         Sock_Connected(sockPtr);
  732.         tcbPtr->state = ESTABLISHED;
  733.         tcbPtr->maxSegSize= MIN(tcbPtr->maxSegSize, 
  734.                     TCPCalcMaxSegSize(tcbPtr));
  735.         packetPtr->data = data;
  736.         packetPtr->dataLen = dataLen;
  737.         (void) Reassemble(sockPtr, tcbPtr, (Net_TCPHeader *)NULL, 
  738.                 packetPtr);
  739.         tcbPtr->send.updateSeqNum = tcpHdrPtr->seqNum - 1;
  740.  
  741.         /* Fall into ... */
  742.  
  743.     /*
  744.      * In the ESTABLISHED state, ignore duplicate and out-of-range ACKs.
  745.      * If the ack is in the range:
  746.      *
  747.      *     tcbPtr->send.unAck < tcpHdrPtr->ackNum <= tcbPtr->send.maxSent
  748.      *
  749.      * then advance tcbPtr->send.unAck to tcpHdrPtr->ackNum and drop
  750.      * data from the retransmission queue.  If this ACK reflects
  751.      * more up-to-date window information, we update our window information.
  752.      */
  753.  
  754.     case ESTABLISHED:
  755.     case FIN_WAIT_1:
  756.     case FIN_WAIT_2:
  757.     case CLOSE_WAIT:
  758.     case CLOSING:
  759.     case LAST_ACK:
  760.     case TIME_WAIT:
  761.  
  762.         if (TCP_SEQ_LE(tcpHdrPtr->ackNum, tcbPtr->send.unAck)) {
  763.         if (dataLen == 0 && tcpHdrPtr->window == tcbPtr->send.window) {
  764.             stats.tcp.recv.dupAck++;
  765.  
  766.             /*
  767.              * If we have outstanding data (not a window probe), or
  768.              * this is a completely duplicate ack (i.e., window info
  769.              * didn't change), the ack is the biggest we've seen
  770.              * and we've seen exactly our rexmt threshhold of
  771.              * them, assume a packet has been dropped and
  772.              * retransmit it.  Kludge send.next & the congestion
  773.              * window so we send only this one packet.  If this packet 
  774.              * fills the only hole in the receiver's seq. space, the 
  775.              * next real ACK will fully open our window. This means we
  776.              * have to do the usual slow-start to not overwhelm an
  777.              * intermediate gateway with a burst of packets.  Leave
  778.              * here with the congestion window set to allow 2 packets
  779.              * on the next real ACK and the exp-to-linear thresh
  780.              * set for half the current window size (since we know
  781.              * we're losing at the current window size).
  782.              */
  783.             if ((tcbPtr->timer[TCP_TIMER_REXMT] == 0) ||
  784.             (tcpHdrPtr->ackNum != tcbPtr->send.unAck)) {
  785.             tcbPtr->dupAcks = 0;
  786.             } else {
  787.             tcbPtr->dupAcks++;
  788.             if (tcbPtr->dupAcks == tcpReXmtThresh) {
  789.                 TCPSeqNum oldNext;
  790.                 unsigned int win;
  791.  
  792.                 oldNext = tcbPtr->send.next;
  793.                 win = 
  794.                    MIN(tcbPtr->send.window, tcbPtr->send.congWindow)
  795.                 / 2 / tcbPtr->maxSegSize;
  796.  
  797.                 if (win < 2) {
  798.                 win = 2;
  799.                 }
  800.                 tcbPtr->send.cwSizeThresh = 
  801.                     win * tcbPtr->maxSegSize;
  802.  
  803.                 tcbPtr->timer[TCP_TIMER_REXMT] = 0;
  804.                 tcbPtr->rtt = 0;
  805.                 tcbPtr->send.next = tcpHdrPtr->ackNum;
  806.                 tcbPtr->send.congWindow = tcbPtr->maxSegSize;
  807.                 (void) TCPOutput(sockPtr, 
  808.                                 tcbPtr);
  809.  
  810.                 if (TCP_SEQ_GT(oldNext, tcbPtr->send.next)) {
  811.                 tcbPtr->send.next = oldNext;
  812.                 }
  813.                 goto drop;
  814.             }
  815.             }
  816.         } else {
  817.             tcbPtr->dupAcks = 0;
  818.         }
  819.         break;
  820.         }
  821.         tcbPtr->dupAcks = 0;
  822.         if (TCP_SEQ_GT(tcpHdrPtr->ackNum, tcbPtr->send.maxSent)) {
  823.         stats.tcp.recv.ackTooMuch++;
  824.         goto dropAfterAck;
  825.         }
  826.         acked = tcpHdrPtr->ackNum - tcbPtr->send.unAck;
  827.         stats.tcp.recv.ackPack++;
  828.         stats.tcp.recv.ackByte += acked;
  829.  
  830.         /*
  831.          * If the transmit timer is running and the timed sequence
  832.          * number was ACKed, update the smoothed round trip time.
  833.          * Since we now have an rtt measurement, cancel the timer
  834.          * backoff (c.f., Phil Karn's retransmit alg.). Recompute
  835.          * the initial retransmit timer.
  836.          */
  837.         if ((tcbPtr->rtt != 0) && 
  838.         TCP_SEQ_GT(tcpHdrPtr->ackNum, tcbPtr->rtseq)) {
  839.  
  840.         stats.tcp.rttUpdated++;
  841.  
  842.         if (tcbPtr->srtt != 0) {
  843.             register int delta;
  844.  
  845.             /*
  846.              * The smoothed rtt is stored as fixed point with 3 bits
  847.              * after the binary point (i.e., scaled by 8).
  848.              * The following magic is equivalentto the smoothing 
  849.              * algorithm in RFC793 with an alpha of .875
  850.              *    srtt = rtt/8 + srtt*7/8 
  851.              * (in fixed point). Adjust the round-trip time to the
  852.              * origin of 0.
  853.              */
  854.  
  855.             delta = tcbPtr->rtt - 1 - (tcbPtr->srtt >>3);
  856.             tcbPtr->srtt += delta;
  857.             if (tcbPtr->srtt <= 0) {
  858.             tcbPtr->srtt = 1;
  859.             }
  860.             /*
  861.              * We accumulate a smoothed RTT variance (actually, a
  862.              * smoothed mean difference), then set the retransmit
  863.              * timer to smoothed RTT + 2 times the smoothed
  864.              * variance.  rttvar is stored as fixed point with 2
  865.              * bits after the binary point (scaled by 4).  The
  866.              * following is equivalent to RFC793 smoothing with an
  867.              * alpha of .75 (rttvar = rttvar*3/4 + |delta| / 4).
  868.              * This replaces RFC793's wired-in beta.
  869.              */
  870.             if (delta < 0) {
  871.             delta = -delta;
  872.             }
  873.             delta -= (tcbPtr->rttvar >> 2);
  874.             tcbPtr->rttvar += delta;
  875.             if (tcbPtr->rttvar <= 0) {
  876.             tcbPtr->rttvar = 1;
  877.             }
  878.         } else {
  879.             /* 
  880.              * No RTT measurement yet - use the unsmoothed RTT.
  881.              * Set the variance to half the RTT (so our first
  882.              * retransmit happens at 2*RTT).
  883.              */
  884.             tcbPtr->srtt = tcbPtr->rtt << 3;
  885.             tcbPtr->rttvar = tcbPtr->rtt << 1;
  886.         }
  887.         tcbPtr->rtt = 0;
  888.         tcbPtr->rxtshift = 0;
  889.         TCP_TIMER_RANGESET(tcbPtr->rxtcur, 
  890.             ((tcbPtr->srtt >> 2) + tcbPtr->rttvar) >> 1,
  891.             TCP_MIN_REXMT_TIME, TCP_MAX_REXMT_TIME);
  892.         }
  893.  
  894.         /*
  895.          * If all outstanding data is acked, stop retransmit
  896.          * timer and remember to restart (more output or persist).
  897.          * If there is more data to be acked, restart retransmit
  898.          * timer.
  899.          */
  900.         if (tcpHdrPtr->ackNum == tcbPtr->send.maxSent) {
  901.         tcbPtr->timer[TCP_TIMER_REXMT] = 0;
  902.         needOutput = TRUE;
  903.         } else if (tcbPtr->timer[TCP_TIMER_PERSIST] == 0) {
  904.         tcbPtr->timer[TCP_TIMER_REXMT] = tcbPtr->rxtcur;
  905.         }
  906.  
  907.         /*
  908.          * When new data is acked, open the congestion window.
  909.          * If the window gives us less than send.cwSizeThresh packets
  910.          * in flight, open exponentially (maxSegSize per packet).
  911.          * Otherwise open linearly (maxSegSize per window,
  912.          * or maxSegSize^2 / congWindow per packet).
  913.          */
  914.         {
  915.         unsigned int incr = tcbPtr->maxSegSize;
  916.  
  917.         if (tcbPtr->send.congWindow > tcbPtr->send.cwSizeThresh) {
  918.             incr = MAX(incr * incr / tcbPtr->send.congWindow, 1);
  919.         }
  920.         tcbPtr->send.congWindow = 
  921.             MIN(tcbPtr->send.congWindow + incr, NET_IP_MAX_PACKET_SIZE);
  922.         }
  923.         { 
  924.         int used;
  925.  
  926.         used = Sock_BufSize(sockPtr, SOCK_SEND_BUF,
  927.                         SOCK_BUF_USED);
  928.         if (acked > used) {
  929.             tcbPtr->send.window -= used;
  930.             Sock_BufRemove(sockPtr, SOCK_SEND_BUF, 
  931.                         used);
  932.             ourFinIsAcked = TRUE;
  933.         } else {
  934.             Sock_BufRemove(sockPtr, SOCK_SEND_BUF,
  935.                     acked);
  936.             tcbPtr->send.window -= acked;
  937.             ourFinIsAcked = FALSE;
  938.         }
  939.         /*
  940.          * Wakeup the waiting writer because there's more room
  941.          * in the buffer now.
  942.          */
  943.         if (ips_Debug) {
  944.             (void) fprintf(stderr,
  945.                 "TCP Input: window opened for writer\n");
  946.         }
  947.         Sock_NotifyWaiter(sockPtr, FS_WRITABLE);
  948.         }
  949.  
  950.         tcbPtr->send.unAck = tcpHdrPtr->ackNum;
  951.         if (TCP_SEQ_LT(tcbPtr->send.next, tcbPtr->send.unAck)) {
  952.         tcbPtr->send.next = tcbPtr->send.unAck;
  953.         }
  954.  
  955.         switch (tcbPtr->state) {
  956.  
  957.         /*
  958.          * In the FIN_WAIT_1 state, in addition to the processing
  959.          * for the ESTABLISHED state, if our FIN is now acknowledged
  960.          * then enter FIN_WAIT_2.
  961.          */
  962.  
  963.         case FIN_WAIT_1:
  964.             if (ourFinIsAcked) {
  965.  
  966.             /*
  967.              * If we can't receive any more data, then the
  968.              * closing user can proceed.  Starting the timer
  969.              * is contrary to the specification, but if we
  970.              * don't get a FIN we'll hang forever.
  971.              */
  972.  
  973.             if (Sock_IsRecvStopped(sockPtr)) {
  974.                 Sock_Disconnected(sockPtr);
  975.                 tcbPtr->timer[TCP_TIMER_2MSL] = tcpMaxIdle;;
  976.             }
  977.             tcbPtr->state = FIN_WAIT_2;
  978.             }
  979.             break;
  980.  
  981.         /*
  982.          * In the CLOSING state, in addition to the processing for
  983.          * the ESTABLISHED state, if the ACK acknowledges our FIN
  984.          * then enter the TIME-WAIT state, otherwise ignore the
  985.          * segment.
  986.          */
  987.         case CLOSING:
  988.             if (ourFinIsAcked) {
  989.             tcbPtr->state = TIME_WAIT;
  990.             TCPCancelTimers(tcbPtr);
  991.             tcbPtr->timer[TCP_TIMER_2MSL] = 2 * TCP_MSL_TIME;
  992.             Sock_Disconnected(sockPtr);
  993.             }
  994.             break;
  995.  
  996.         /*
  997.          * The only thing that can arrive in the LAST_ACK state
  998.          * is an acknowledgment of our FIN.  If our FIN is now
  999.          * acknowledged, delete the TCB, enter the closed state
  1000.          * and return.
  1001.          */
  1002.         case LAST_ACK:
  1003.             if (ourFinIsAcked) {
  1004.             TCPCloseConnection(sockPtr, tcbPtr);
  1005.             tcbPtr = NULL;
  1006.             }
  1007.             goto drop;
  1008.  
  1009.         /*
  1010.          * In the TIME_WAIT state, the only thing that should arrive
  1011.          * is a retransmission of the remote FIN.  Acknowledge
  1012.          * it and restart the finack timer.
  1013.          */
  1014.         case TIME_WAIT:
  1015.             tcbPtr->timer[TCP_TIMER_2MSL] = 2 * TCP_MSL_TIME;
  1016.             goto dropAfterAck;
  1017.         }
  1018.  
  1019.     default:
  1020.         break;
  1021.  
  1022.     }
  1023.  
  1024. updateWindow:
  1025.  
  1026.     /*
  1027.      * p. 72
  1028.      *
  1029.      * Update window information. Don't look at the info if the ACK is 
  1030.      * missing (TAC's send garbage on the first SYN).
  1031.      */
  1032.  
  1033.     if ((headerFlags & NET_TCP_ACK_FLAG) &&
  1034.      (TCP_SEQ_LT(tcbPtr->send.updateSeqNum, tcpHdrPtr->seqNum) ||
  1035.       tcbPtr->send.updateSeqNum == tcpHdrPtr->seqNum &&
  1036.          (TCP_SEQ_LT(tcbPtr->send.updateAckNum, tcpHdrPtr->ackNum) ||
  1037.           tcbPtr->send.updateAckNum == tcpHdrPtr->ackNum && 
  1038.           tcpHdrPtr->window > tcbPtr->send.window
  1039.          )
  1040.       )
  1041.     ) {
  1042.  
  1043.     /* 
  1044.      * Keep track of pure window updates.
  1045.      */
  1046.     if (dataLen == 0 &&
  1047.         tcbPtr->send.updateAckNum == tcpHdrPtr->ackNum && 
  1048.         tcpHdrPtr->window > tcbPtr->send.window) {
  1049.         stats.tcp.recv.winUpd++;
  1050.     }
  1051.     tcbPtr->send.window      = tcpHdrPtr->window;
  1052.     tcbPtr->send.updateSeqNum = tcpHdrPtr->seqNum;
  1053.     tcbPtr->send.updateAckNum = tcpHdrPtr->ackNum;
  1054.     if (tcbPtr->send.window > tcbPtr->send.maxWindow) {
  1055.         tcbPtr->send.maxWindow = tcbPtr->send.window;
  1056.     }
  1057.     needOutput = TRUE;
  1058.     }
  1059.  
  1060.     /*
  1061.      * p. 73
  1062.      *
  1063.      * Step 6: check the URG bit.
  1064.      *
  1065.      * Process segments with urgent data.
  1066.      */
  1067.  
  1068.     if ((headerFlags & NET_TCP_URG_FLAG) && 
  1069.     (tcpHdrPtr->urgentOffset != 0) &&
  1070.     !TCP_HAVE_RECVD_FIN(tcbPtr->state)) {
  1071.  
  1072.     /*
  1073.      * This is a kludge, but if we receive and accept random urgent
  1074.      * pointers, we'll crash in the read routine.  It's hard to
  1075.      * imagine someone actually wanting to send this much urgent data.
  1076.      */
  1077.  
  1078.     if ((tcpHdrPtr->urgentOffset + 
  1079.          Sock_BufSize(sockPtr, SOCK_RECV_BUF, 
  1080.                 SOCK_BUF_USED)) > 
  1081.         Sock_BufSize(sockPtr,
  1082.                 SOCK_RECV_BUF, SOCK_BUF_MAX_SIZE)) {
  1083.         tcpHdrPtr->urgentOffset = 0;        /* XXX */
  1084.         headerFlags &= ~NET_TCP_URG_FLAG;        /* XXX */
  1085.     } else {
  1086.  
  1087.         /*
  1088.          * If this segment advances the known urgent pointer, then
  1089.          * mark the data stream.  This should not happen in
  1090.          * CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT states since a
  1091.          * FIN has been received from the remote side.  In these
  1092.          * states, we ignore the URG.
  1093.          *
  1094.          * According to RFC1011 (Assigned Internet Protocols), the urgent
  1095.          * pointer points to the last octet of urgent data.  We
  1096.          * continue, however, to consider it to indicate the first
  1097.          * octet of data past the urgent section as the original spec
  1098.          * states.
  1099.          */
  1100.  
  1101.         if (TCP_SEQ_GT(tcpHdrPtr->seqNum + tcpHdrPtr->urgentOffset, 
  1102.                 tcbPtr->recv.urgentPtr)) {
  1103.  
  1104.         tcbPtr->recv.urgentPtr = tcpHdrPtr->seqNum + 
  1105.                          tcpHdrPtr->urgentOffset;
  1106.         
  1107.         tcbPtr->urgentBufPos = 
  1108.             Sock_BufSize(sockPtr, 
  1109.                     SOCK_RECV_BUF, SOCK_BUF_USED) + 
  1110.                 tcbPtr->recv.urgentPtr - tcbPtr->recv.next - 1;
  1111.         if (tcbPtr->urgentBufPos == 0) {
  1112.             Sock_UrgentDataNext(sockPtr);
  1113.         }
  1114.         Sock_HaveUrgentData(sockPtr);
  1115.         tcbPtr->flags &= ~(TCP_HAVE_URGENT_DATA | TCP_HAD_URGENT_DATA);
  1116.         stats.tcp.recv.urgent++;
  1117.         }
  1118.  
  1119.         /*
  1120.          * Remove urgent data from the segment so it doesn't get 
  1121.          * presented to the user in the receive buffer. (It is still 
  1122.          * reflected in the segment length for sequencing purposes.) 
  1123.          * This can happen independent of advancing the URG pointer, 
  1124.          * but if two URG's are pending at once, some urgent data may 
  1125.          * creep in... ick.
  1126.          */
  1127.  
  1128.         if ((tcpHdrPtr->urgentOffset <= dataLen) &&
  1129.         !Sock_IsOptionSet(sockPtr, 
  1130.                     NET_OPT_OOB_INLINE)) {
  1131.  
  1132.         int    urgentOffset = tcpHdrPtr->urgentOffset -1;
  1133.  
  1134.         if (urgentOffset > dataLen) {
  1135.             (void) fprintf(stderr, 
  1136.               "Warning: TCP Input: urgent data not in segment\n");
  1137.         } else {
  1138.             Address urgData = data;
  1139.             urgData          += urgentOffset;
  1140.             tcbPtr->urgentData     = *urgData;
  1141.             tcbPtr->flags     |= TCP_HAVE_URGENT_DATA;
  1142.             bcopy( urgData+1, urgData, dataLen - urgentOffset -1);
  1143.             dataLen--;
  1144.             /*
  1145.              * Make sure an ACK is sent if the packet just contained
  1146.              * urgent data. Step 7 is not done if dataLen is 0 so
  1147.              * we must set the ACK flag here.
  1148.              */
  1149.             if ((dataLen == 0) &&
  1150.             (tcpHdrPtr->seqNum == tcbPtr->recv.next)) {
  1151.             tcbPtr->recv.next++;
  1152.             tcbPtr->flags |= TCP_DELAY_ACK;
  1153.             stats.tcp.recv.urgentOnly++;
  1154.             }
  1155.         }
  1156.         }
  1157.     }
  1158.     } else {
  1159.     /*
  1160.      * If no urgent data are expected, pull receive urgent pointer 
  1161.      * along with the receive window.
  1162.      */
  1163.     if (TCP_SEQ_GT(tcbPtr->recv.next, tcbPtr->recv.urgentPtr)) {
  1164.         tcbPtr->recv.urgentPtr = tcbPtr->recv.next;
  1165.     }
  1166.     }
  1167.  
  1168.  
  1169.     /*
  1170.      * p. 74
  1171.      *
  1172.      * Step 7:  Process the segment data.
  1173.      *
  1174.      * The data is merged into the TCP sequencing queue, and acknowledgment 
  1175.      * of receipt is arranged, if necessary.  This process logically involves 
  1176.      * adjusting tcbPtr->recv.window as data is presented to the user.  If 
  1177.      * a FIN has already been received on this connection then we just ignore 
  1178.      * the data.
  1179.      */
  1180.  
  1181.     if ( ((dataLen != 0) || (headerFlags & NET_TCP_FIN_FLAG)) &&
  1182.     !TCP_HAVE_RECVD_FIN(tcbPtr->state)) {
  1183.  
  1184.     int len;
  1185.  
  1186.     /*
  1187.      * Check for the common case before calling Reassemble(): the new
  1188.      * segment is the next one to be received on an established
  1189.      * connection and the reassembly queue is empty.
  1190.      */
  1191.  
  1192.     if ((tcpHdrPtr->seqNum == tcbPtr->recv.next) &&
  1193.         List_IsEmpty(&tcbPtr->reassList) &&
  1194.         (tcbPtr->state == ESTABLISHED)) {
  1195.  
  1196.         int bytesWritten;
  1197.  
  1198.         tcbPtr->recv.next += dataLen; 
  1199.         headerFlags = tcpHdrPtr->flags & NET_TCP_FIN_FLAG; 
  1200.         stats.tcp.recv.pack++;
  1201.         stats.tcp.recv.byte += dataLen;
  1202.         if ((Sock_BufAppend(sockPtr, 
  1203.                 SOCK_RECV_BUF, FALSE, dataLen, data, 
  1204.                 packetPtr->base, (Net_InetSocketAddr *) NULL,
  1205.                 &bytesWritten) != SUCCESS)
  1206.             || (bytesWritten != dataLen)) {
  1207.         (void) fprintf(stderr, 
  1208.             "Warning: (TCP)Input: append to recv buffer failed\n");
  1209.         }
  1210.  
  1211.         if (ips_Debug) {
  1212.         (void) fprintf(stderr, 
  1213.             "TCP Input: appended %d bytes: '%.*s'\n", 
  1214.                 dataLen, MIN(dataLen, 20), data);
  1215.         }
  1216.         Sock_NotifyWaiter(sockPtr, FS_READABLE);
  1217.         tcbPtr->flags |= TCP_DELAY_ACK;
  1218.     } else {
  1219.         /*
  1220.          * ACK immediately when segments are out of order so fast 
  1221.          * retransmission can work.
  1222.          */
  1223.         tcbPtr->flags |= TCP_ACK_NOW;
  1224.         packetPtr->data = data;
  1225.         packetPtr->dataLen = dataLen;
  1226.         headerFlags = Reassemble(sockPtr, tcbPtr, tcpHdrPtr, packetPtr);
  1227.     } 
  1228.     /*
  1229.      * Don't free the packet memory when we leave this routine because
  1230.      * the packet is now on the reassembly queue or in the socket's
  1231.      * receive buffer.
  1232.      */
  1233.     freePacket = FALSE;
  1234.  
  1235.     /*
  1236.      * Note the amount of data that peer has sent into our window, 
  1237.      * in order to estimate the sender's buffer size.
  1238.      */
  1239.     len = Sock_BufSize(sockPtr, SOCK_RECV_BUF, 
  1240.             SOCK_BUF_MAX_SIZE) -
  1241.             (tcbPtr->recv.next - tcbPtr->recv.advtWindow);
  1242.     if (len > tcbPtr->recv.maxWindow) {
  1243.         tcbPtr->recv.maxWindow = len;
  1244.     }
  1245.     } else {
  1246.     headerFlags &= ~NET_TCP_FIN_FLAG;
  1247.     }
  1248.  
  1249.  
  1250.     /*
  1251.      * p. 75
  1252.      *
  1253.      * Step 8: check the FIN bit.
  1254.      *
  1255.      * If a FIN is received, ACK the FIN and let the user know that 
  1256.      * the connection is closing.
  1257.      */
  1258.  
  1259.     if (headerFlags & NET_TCP_FIN_FLAG) {
  1260.     if (!TCP_HAVE_RECVD_FIN(tcbPtr->state)) {
  1261.         Sock_StopRecv(sockPtr);
  1262.         tcbPtr->flags |= TCP_ACK_NOW;
  1263.         tcbPtr->recv.next++;
  1264.     }
  1265.     switch (tcbPtr->state) {
  1266.  
  1267.         /*
  1268.          * In the SYN_RECEIVED and ESTABLISHED states, enter the 
  1269.          * CLOSE_WAIT state.
  1270.          */
  1271.         case SYN_RECEIVED:
  1272.         case ESTABLISHED:
  1273.         tcbPtr->state = CLOSE_WAIT;
  1274.         break;
  1275.  
  1276.         /*
  1277.          * If still in the FIN_WAIT_1 state, our FIN has not been acked so
  1278.          * enter the CLOSING state.
  1279.          */
  1280.         case FIN_WAIT_1:
  1281.         tcbPtr->state = CLOSING;
  1282.         break;
  1283.  
  1284.         /*
  1285.          * In the FIN_WAIT_2 state, enter the TIME_WAIT state and start
  1286.          * the time-wait timer, turning off the other standard timers.
  1287.          */
  1288.         case FIN_WAIT_2:
  1289.         tcbPtr->state = TIME_WAIT;
  1290.         TCPCancelTimers(tcbPtr);
  1291.         tcbPtr->timer[TCP_TIMER_2MSL] = 2 * TCP_MSL_TIME;
  1292.         Sock_Disconnected(sockPtr);
  1293.         break;
  1294.  
  1295.         /*
  1296.          * In the TIME_WAIT state, restart the 2*MSL time-wait timer.
  1297.          */
  1298.         case TIME_WAIT:
  1299.         tcbPtr->timer[TCP_TIMER_2MSL] = 2 * TCP_MSL_TIME;
  1300.         break;
  1301.     }
  1302.     }
  1303.  
  1304.     if (Sock_IsOptionSet(sockPtr, NET_OPT_DEBUG)) {
  1305.     TCPTrace(TCP_TRACE_INPUT, oldState, tcbPtr, &saveHeader, dataLen);
  1306.     }
  1307.  
  1308.     /*
  1309.      * Return any desired output.
  1310.      */
  1311.     if (needOutput || (tcbPtr->flags & TCP_ACK_NOW)) {
  1312.     (void) TCPOutput(sockPtr, tcbPtr);
  1313.     }
  1314.  
  1315.     if (freePacket) {
  1316.     free(packetPtr->base);
  1317.     }
  1318.     return;
  1319.  
  1320.  
  1321. dropAfterAck:
  1322.  
  1323.     /*
  1324.      * Generate an ACK dropping incoming segment if it occupies
  1325.      * sequence space, where the ACK reflects our state.
  1326.      */
  1327.     if (headerFlags & NET_TCP_RST_FLAG) {
  1328.     goto drop;
  1329.     }
  1330.     if (Sock_IsOptionSet(sockPtr, NET_OPT_DEBUG)) {
  1331.     TCPTrace(TCP_TRACE_RESPOND, oldState, tcbPtr, &saveHeader, dataLen);
  1332.     }
  1333.     TCPRespond(sockPtr, tcpHdrPtr, ipHdrPtr, 
  1334.             tcbPtr->recv.next, tcbPtr->send.next, NET_TCP_ACK_FLAG);
  1335.     free(packetPtr->base);
  1336.     return;
  1337.  
  1338.  
  1339. dropWithReset:
  1340.  
  1341.     /*
  1342.      * Generate a RESET, dropping incoming segment.
  1343.      * Make ACK acceptable to originator of segment.
  1344.      * Don't bother to respond if destination was broadcast.
  1345.      */
  1346.  
  1347.     if ((headerFlags & NET_TCP_RST_FLAG) || 
  1348.     Rte_IsBroadcastAddr(ipHdrPtr->dest)) {
  1349.     goto drop;
  1350.     }
  1351.     if (headerFlags & NET_TCP_ACK_FLAG) {
  1352.     TCPRespond(sockPtr,
  1353.                tcpHdrPtr, ipHdrPtr, (TCPSeqNum)0, 
  1354.             tcpHdrPtr->ackNum, NET_TCP_RST_FLAG);
  1355.     } else {
  1356.     if (headerFlags & NET_TCP_SYN_FLAG) {
  1357.         dataLen++;
  1358.     }
  1359.     TCPRespond(sockPtr, tcpHdrPtr, ipHdrPtr,  
  1360.             tcpHdrPtr->seqNum + dataLen, 
  1361.             (TCPSeqNum)0, NET_TCP_RST_FLAG|NET_TCP_ACK_FLAG);
  1362.     }
  1363.     free(packetPtr->base);
  1364.     return;
  1365.  
  1366.  
  1367. drop:
  1368.  
  1369.     /*
  1370.      * Drop space held by incoming segment and return.
  1371.      */
  1372.  
  1373.     if ((tcbPtr != NULL) && 
  1374.     (sockPtr != NULL) && 
  1375.     Sock_IsOptionSet(sockPtr, NET_OPT_DEBUG)) {
  1376.     TCPTrace(TCP_TRACE_DROP, oldState, tcbPtr, &saveHeader, dataLen);
  1377.     }
  1378.     free(packetPtr->base);
  1379.     return;
  1380. }
  1381.  
  1382.  
  1383.  
  1384. /*
  1385.  *----------------------------------------------------------------------
  1386.  *
  1387.  * CalcFreeSpace --
  1388.  *
  1389.  *    Calculate amount of space in the receive window.
  1390.  *    The Receive window is amount of space in the receive queue,
  1391.  *    but not less than the advertised window.
  1392.  *
  1393.  * Results:
  1394.  *    None.
  1395.  *
  1396.  * Side effects:
  1397.  *    None.
  1398.  *
  1399.  *----------------------------------------------------------------------
  1400.  */
  1401.  
  1402. static void
  1403. CalcFreeSpace(sockPtr, tcbPtr)
  1404.     Sock_InfoPtr    sockPtr;
  1405.     TCPControlBlock     *tcbPtr;
  1406. {
  1407.     int win;
  1408.  
  1409.     win = Sock_BufSize(sockPtr, SOCK_RECV_BUF, SOCK_BUF_FREE);
  1410.     if (win < 0) { 
  1411.     win = 0;
  1412.     }
  1413.     tcbPtr->recv.window = 
  1414.         MAX(win, (int)(tcbPtr->recv.advtWindow - tcbPtr->recv.next));
  1415. }
  1416.  
  1417.  
  1418. /*
  1419.  *----------------------------------------------------------------------
  1420.  *
  1421.  * ProcessOptions --
  1422.  *
  1423.  *    Decode the options that follow the TCP header.
  1424.  *    There is currently just one option: the maximum segment size.
  1425.  *
  1426.  * Results:
  1427.  *    None.
  1428.  *
  1429.  * Side effects:
  1430.  *    The maximum segment size of the tcb is updated.
  1431.  *
  1432.  *----------------------------------------------------------------------
  1433.  */
  1434.  
  1435. static void
  1436. ProcessOptions(len, tcpHdrPtr, tcbPtr)
  1437.     int            len;        /* Length of the TCP basic header 
  1438.                      * and options. */
  1439.     Net_TCPHeader    *tcpHdrPtr;    /* Ptr to start of the TCP header. */
  1440.     TCPControlBlock    *tcbPtr;    /* The TCB to be updated. */
  1441. {
  1442.     register unsigned char *cp;
  1443.     int option;
  1444.     int optionLen;
  1445.     int maxSegSize;
  1446.  
  1447.     cp = (unsigned char *) tcpHdrPtr;
  1448.     
  1449.     for (len -= sizeof(Net_TCPHeader); len > 0; 
  1450.      len -= optionLen, cp += optionLen) {
  1451.  
  1452.     option = cp[0];
  1453.     if (option == NET_TCP_OPTION_EOL) {
  1454.         break;
  1455.     }
  1456.     if (option == NET_TCP_OPTION_NOP) {
  1457.         optionLen = 1;
  1458.     } else {
  1459.         optionLen = cp[1];
  1460.         if (optionLen <= 0) {
  1461.         break;
  1462.         }
  1463.     }
  1464.     switch (option) {
  1465.  
  1466.         case NET_TCP_OPTION_MAX_SEG_SIZE:
  1467.         if (optionLen != 4) {
  1468.             continue;
  1469.         }
  1470.         if (!(tcpHdrPtr->flags & NET_TCP_SYN_FLAG)) {
  1471.             continue;
  1472.         }
  1473.         maxSegSize = Net_NetToHostShort(*(unsigned short *)(cp + 2));
  1474.         tcbPtr->maxSegSize = MIN(maxSegSize, TCPCalcMaxSegSize(tcbPtr));
  1475.         break;
  1476.  
  1477.         default:
  1478.             break;
  1479.  
  1480.     }
  1481.     }
  1482. }
  1483.  
  1484.  
  1485. /*
  1486.  *----------------------------------------------------------------------
  1487.  *
  1488.  * TCPCalcMaxSegSize --
  1489.  *
  1490.  *    Determines a reasonable value for the maximum segment size.
  1491.  *    The value depends on the route to the remote peer.  If
  1492.  *    the peer is on the local net, we output a size based on the
  1493.  *    maximum size on the local net.  (This includes other subnets on
  1494.  *    our net -- see Rte_IsLocal.)  If the peer is remote, return
  1495.  *    TCP_MAX_SEG_SIZE, which is on the order of 500 bytes and should
  1496.  *    never need to be fragmented by another IP server.
  1497.  *
  1498.  * Results:
  1499.  *    The maximum segment size is returned.
  1500.  *
  1501.  * Side effects:
  1502.  *    None.
  1503.  *
  1504.  *----------------------------------------------------------------------
  1505.  */
  1506.  
  1507. /*ARGSUSED*/
  1508. int
  1509. TCPCalcMaxSegSize(tcbPtr)
  1510.     TCPControlBlock *tcbPtr;
  1511. {
  1512.     register Net_IPHeader *ipHdrPtr;
  1513.     Rte_NetID        netID;
  1514.     int localOutSize;
  1515.     int maxOutSize = TCP_MAX_SEG_SIZE;
  1516.     int subnet;
  1517.  
  1518.     ipHdrPtr = tcbPtr->IPTemplatePtr;
  1519.     if (ipHdrPtr != ((Net_IPHeader *) NULL)) {
  1520.     if (!Rte_FindOutputNet(ipHdrPtr->dest,  &netID, &localOutSize)) {
  1521.         return(TCP_MAX_SEG_SIZE);
  1522.     }
  1523.     maxOutSize = localOutSize - sizeof(Net_TCPHeader) -
  1524.         sizeof(Net_IPHeader);
  1525.     if (Rte_IsLocalAddr(netID)) {
  1526. #ifdef DEBUG_SIZE
  1527.         (void) fprintf(stderr,
  1528.                "TCPCalcMaxSegSize: host is local, size %d\n",
  1529.                maxOutSize);
  1530. #endif
  1531.         return(maxOutSize);
  1532.     }
  1533.     maxOutSize = MIN(maxOutSize, TCP_MAX_SEG_SIZE);
  1534.     tcbPtr->send.congWindow = maxOutSize;
  1535. #ifdef DEBUG_SIZE
  1536.         (void) fprintf(stderr,
  1537.                "TCPCalcMaxSegSize: host is remote, size %d\n",
  1538.                maxOutSize);
  1539. #endif
  1540.     } else {
  1541. #ifdef DEBUG_SIZE
  1542.     (void) fprintf(stderr,
  1543.                "TCPCalcMaxSegSize: no ipHdrPtr\n");
  1544. #endif
  1545.     }    
  1546.     return (maxOutSize);
  1547. }
  1548.  
  1549.  
  1550.  
  1551.  
  1552. /*
  1553.  *----------------------------------------------------------------------
  1554.  *
  1555.  * Reassemble --
  1556.  *
  1557.  *    Reassembles out-of-order data segments for a TCB.
  1558.  *
  1559.  * Results:
  1560.  *    If not 0, the TCP header flags of the reassembled data.
  1561.  *
  1562.  * Side effects:
  1563.  *    Data may be appended to the socket's receive buffer.
  1564.  *
  1565.  *----------------------------------------------------------------------
  1566.  */
  1567.  
  1568. static unsigned short
  1569. Reassemble(sockPtr, tcbPtr, tcpHdrPtr, packetPtr)
  1570.     Sock_InfoPtr        sockPtr;    /* Socket of interest. */
  1571.     TCPControlBlock         *tcbPtr;    /* TCB for the socket. */
  1572.     register Net_TCPHeader    *tcpHdrPtr;    /* Header of the incoming 
  1573.                          * packet. */
  1574.     register IPS_Packet        *packetPtr;    /* Descriptor of the incoming
  1575.                          * packet. */
  1576. {
  1577.     register ReassElement    *reassPtr;
  1578.     ReassElement    *tempPtr;
  1579.     unsigned short    flags;
  1580.     Boolean        notifyNeeded;
  1581.     List_Links        *listPtr;
  1582.     register int    dataLen;
  1583.  
  1584.     listPtr = &tcbPtr->reassList;
  1585.     dataLen = packetPtr->dataLen;
  1586.  
  1587.     /*
  1588.      * If we're called with tcpHdrPtr == NULL after entering the ESTABLISHED 
  1589.      * state, then force pre-ESTABLISHED data up to user socket.
  1590.      */
  1591.  
  1592.     if (tcpHdrPtr != (Net_TCPHeader *) NULL) {
  1593.  
  1594.     /*
  1595.      * Find a segment which begins after this one does
  1596.      * (the sequence # will be greater than the seq. # of the new
  1597.      * segment).
  1598.      */
  1599.     LIST_FORALL(listPtr, (List_Links *)reassPtr) {
  1600.         if (TCP_SEQ_GT(reassPtr->seqNum, tcpHdrPtr->seqNum)) {
  1601.         break;
  1602.         }
  1603.     }
  1604.  
  1605.     /*
  1606.      * If there is a preceding segment, it may provide some of
  1607.      * our data already.  If so, drop the data from the incoming
  1608.      * segment.  If the preceding segment provides all of our data, 
  1609.      * drop the new segment.
  1610.      *
  1611.      * reassPtr now points to the next segment or the end of the list.
  1612.      * If there is a previous segment, the List_Prev of reassPtr should
  1613.      * not be the end of the list.
  1614.      */
  1615.     if (!List_IsAtEnd(listPtr, List_Prev((List_Links *)reassPtr))) {
  1616.         register int i;
  1617.  
  1618.         reassPtr = (ReassElement *) List_Prev((List_Links *)reassPtr);
  1619.  
  1620.         /*
  1621.          * Check for overlap of new and old data:
  1622.          *
  1623.          *              new s#
  1624.          *           i: |--|--|
  1625.          *               + 0 -
  1626.          *
  1627.          *     +--- old ---+
  1628.          *    seq#       s#+len
  1629.          *
  1630.          * If i is positive, then the new segment overlaps with
  1631.          * the old. If it's 0 or negative then there's no overlap.
  1632.          */
  1633.  
  1634.         /* conversion to int (in i) handles seq wraparound */
  1635.         i = (reassPtr->seqNum + reassPtr->len) - tcpHdrPtr->seqNum;
  1636.  
  1637.         if (i > 0) {
  1638.         /*
  1639.          * Overlap. If i is greater than the length of the new
  1640.          * segment, then the old segment completely overlaps
  1641.          * the new one so it duplicates data and it can be dropped.
  1642.          */
  1643.         if (i >= dataLen) {
  1644.             stats.tcp.recv.dupPack++;
  1645.             stats.tcp.recv.dupByte += dataLen;
  1646.             free(packetPtr->base);
  1647.             return(0);
  1648.         }
  1649.         /*
  1650.          * Partial overlap. Trim data from the end of the new segment.
  1651.          */
  1652.         dataLen        -= i;
  1653.         packetPtr->data    += i;
  1654.         tcpHdrPtr->seqNum += i;
  1655.         }
  1656.         reassPtr = (ReassElement *) List_Next((List_Links *)reassPtr);
  1657.     }
  1658.     stats.tcp.recv.ooPack++;
  1659.     stats.tcp.recv.ooByte += dataLen;
  1660.  
  1661.     /*
  1662.      * Now see if the new segment overlaps succeeding segments.
  1663.      * If so, then trim or delete the old ones.
  1664.      */
  1665.     while (!List_IsAtEnd(listPtr, (List_Links *)reassPtr)) {
  1666.         register int i;
  1667.  
  1668.         /*
  1669.          * Determine how much overlap there is. If i is 0 or negative
  1670.          * then, there's no overlap. If i is greater than the length
  1671.          * of the old segment, then the new segment completely covers it.
  1672.          */
  1673.         i = (tcpHdrPtr->seqNum + dataLen) - reassPtr->seqNum;
  1674.         if (i <= 0) {
  1675.         break;
  1676.         }
  1677.         if (i < reassPtr->len) {
  1678.         /*
  1679.          * Partial overlap. Trim data from the front of the old segment.
  1680.          */
  1681.         reassPtr->seqNum += i;
  1682.         reassPtr->len    -= i;
  1683.         reassPtr->data    += i;
  1684.         break;
  1685.         }
  1686.         /*
  1687.          * Complete overlap. Remove the old segment.
  1688.          */
  1689.         tempPtr = (ReassElement *)List_Next((List_Links *)reassPtr);
  1690.         List_Remove((List_Links *)reassPtr);
  1691.         free(reassPtr->base);
  1692.         free((char *) reassPtr);
  1693.         reassPtr = tempPtr;
  1694.     }
  1695.  
  1696.     /*
  1697.      * Stick new segment in its place.
  1698.      */
  1699.     tempPtr = (ReassElement *) malloc(sizeof(ReassElement));
  1700.     List_InitElement((List_Links *) tempPtr);
  1701.     tempPtr->len = dataLen;
  1702.     tempPtr->data = packetPtr->data;
  1703.     tempPtr->base = packetPtr->base;
  1704.     tempPtr->seqNum = tcpHdrPtr->seqNum;
  1705.     tempPtr->flags = tcpHdrPtr->flags;
  1706.     List_Insert((List_Links *)tempPtr, LIST_BEFORE((List_Links *)reassPtr));
  1707.     }
  1708.  
  1709.     /*
  1710.      * Go through the reassembly queue and append the first contigous chunk 
  1711.      * of the segment to the socket receive buffer. Stop when a gap is found
  1712.      * or the end of the list is reached.
  1713.      */
  1714.  
  1715.     if (!TCP_HAVE_RECVD_SYN(tcbPtr->state)) {
  1716.     return(0);
  1717.     }
  1718.     reassPtr = (ReassElement *) List_First(listPtr);
  1719.     if (List_IsAtEnd(listPtr, (List_Links *)reassPtr) ||
  1720.     (reassPtr->seqNum != tcbPtr->recv.next)) {
  1721.     return(0);
  1722.     }
  1723.     if ((tcbPtr->state == SYN_RECEIVED) && (dataLen != 0)) {
  1724.     return(0);
  1725.     }
  1726.  
  1727.     notifyNeeded = FALSE;
  1728.     do {
  1729.     tcbPtr->recv.next += reassPtr->len;
  1730.     flags = reassPtr->flags & NET_TCP_FIN_FLAG;
  1731.     tempPtr = (ReassElement *)List_Next((List_Links *) reassPtr);
  1732.     List_Remove((List_Links *)reassPtr);
  1733.     if (Sock_IsRecvStopped(sockPtr)) {
  1734.         free(reassPtr->base);
  1735.     } else {
  1736.         int amt;
  1737.  
  1738.         if ((Sock_BufAppend(sockPtr,
  1739.                 SOCK_RECV_BUF, FALSE, reassPtr->len,
  1740.                 reassPtr->data, reassPtr->base, 
  1741.                 (Net_InetSocketAddr *) NULL,
  1742.                 &amt) != SUCCESS) || (amt != reassPtr->len)) {
  1743.         if (amt == 0) {
  1744.             free(reassPtr->base);
  1745.         }
  1746.         }
  1747.         if (ips_Debug) {
  1748.         (void) fprintf(stderr, 
  1749.             "TCP Reassemble: appended %d bytes: '%.*s'\n",
  1750.                 amt, MIN(amt, 20), reassPtr->data);
  1751.                 
  1752.         }
  1753.         notifyNeeded = TRUE;
  1754.     }
  1755.     free((char *) reassPtr);
  1756.     reassPtr = tempPtr;
  1757.     } while (!List_IsAtEnd(listPtr, (List_Links *)reassPtr) && 
  1758.         (reassPtr->seqNum == tcbPtr->recv.next));
  1759.  
  1760.     if (notifyNeeded) {
  1761.     Sock_NotifyWaiter(sockPtr, FS_READABLE);
  1762.     }
  1763.     return(flags);
  1764. }
  1765.  
  1766.  
  1767. /*
  1768.  *----------------------------------------------------------------------
  1769.  *
  1770.  * TCPCleanReassList --
  1771.  *
  1772.  *    Removes all segments on the reassembly list of a TCP control block.
  1773.  *
  1774.  * Results:
  1775.  *    None.
  1776.  *
  1777.  * Side effects:
  1778.  *    Memory for the reassembly information and packets are deallocated.
  1779.  *
  1780.  *----------------------------------------------------------------------
  1781.  */
  1782.  
  1783. void
  1784. TCPCleanReassList(tcbPtr)
  1785.     TCPControlBlock     *tcbPtr;    /* TCB containing a reassembly Q. */
  1786. {
  1787.     List_Links    *ptr;
  1788.     List_Links    *tempPtr;
  1789.  
  1790.     LIST_FORALL(&tcbPtr->reassList, ptr) {
  1791.     tempPtr = List_Next(ptr);
  1792.     List_Remove(ptr);
  1793.     free((char *) ((ReassElement *)ptr)->base);
  1794.     free((char *) ptr);
  1795.     ptr = tempPtr;
  1796.     }
  1797. }
  1798.